
from Framing_Pre_Emphasis import max_index, signal
import numpy as np
from scipy.fftpack.basic import ifft,fft
from scipy.io import wavfile

def read_audio(filename):
    sample_rate, signal = wavfile.read(filename,"rb")
    #read the format inofrmation
    num_frames, num_channels = signal.shape
    wave_data = signal[:,0]
    time = np.arange(0 ,num_frames) * (1.0/sample_rate)
    return wave_data,time,sample_rate,num_frames

def emphasis(signal,emp_factor):
    emphasized_signal1 = np.array(signal[1:]) - (emp_factor) * np.array(signal[:-1])
    emphasized_signal = np.append(signal[0],emphasized_signal1)
    return emphasized_signal

def framing(signal,frame_size,frame_stride,sample_rate,signal_length):
    frame_length = round(frame_size * sample_rate) 
    frame_step = round(frame_stride * sample_rate)
    max_index = round((signal_length - frame_length)/ frame_step)
    signal_frame = np.zeros((max_index,frame_length),dtype = np.complex)
    for n in range(0,max_index):
        signal_frame[n] = np.array(signal[n*frame_step:n*frame_step + frame_length])
    return signal_frame

def runing_average(data,size):
    mean = []
    for i in range(len(data)):
        if i == len(data)-size:
            break
        frame = data[i:i+size]
        mean.append(np.mean(frame))
        #mean.append(data[-1:-1-size])
    return mean

def zero_crossing_rate(data,delta):
    zero_crossing_rate=np.zeros((len(data)))
    for i in range(len(data)):
        #substract the mean value to block DC components
        #normalize wave stream 
        wave = (data[i] - np.mean(data[i]))/max(np.abs(data[i])) 
        #print(data[i])
        frame1 = wave[:-1]
        frame2 = wave[1:]
        signs = frame1*frame2 <0
        diff = np.abs(frame1-frame2) > delta
        #print(diff)
        zero_crossing_rate[i] = np.sum(signs * diff)
        #print(zero_crossing_rate[i])
    return zero_crossing_rate

def frame_fft (frame):
    max_index,length = frame.shape
    fft_frame = np.zeros((frame.shape),dtype = np.complex)
    for i in range(0,max_index):
        fft_frame[i]= fft(frame[i])
    return fft_frame

def frame_ifft (frame):
    max_index,length = frame.shape
    ifft_frame = np.zeros((frame.shape),dtype = np.complex)
    for i in range(0,max_index):
        ifft_frame[i] = ifft(frame[i])
    return ifft_frame

def frame_ifft_LPF(frame,fre_band,noise ):
    freq_filter = abs(fre_band) < noise #filter high frequency noise
    max_index,length = frame.shape
    ifft_frame = np.zeros((frame.shape),dtype = np.complex)
    for i in range(max_index):
        fil_sig = frame[i] * freq_filter # discard noise
        ifft_frame[i] = ifft(fil_sig)
    return ifft_frame

def frame_reconstruct(frame,step):
    max_index, length = frame.shape
    temp = np.zeros((max_index-1,step))
    signal = frame[0]
    for i in range(max_index-1):
        temp[i]= frame[i+1][-step:]
    for i in range(max_index-1):
        signal = np.append(signal,temp[i])
    return signal

def hyst(x, th_lo, th_hi=None, initial = False):
    if th_hi is None:
        th_hi = th_lo + np.finfo(np.float32).eps
    hi = x >= th_hi
    lo_or_hi = (x <= th_lo) | hi
    ind = np.nonzero(lo_or_hi)[0]
    if not ind.size: # prevent index error if ind is empty
        return np.zeros_like(x, dtype=bool) | initial
    cnt = np.cumsum(lo_or_hi) # from 0 to len(x)
    oo = ind[cnt-1]
    ooo = hi[ind[cnt-1]]
    hst = np.where(cnt, hi[ind[cnt-1]], initial)
    loc = np.where(np.diff(hst))[0]
    A = loc[np.where(hst[loc] ^ True)]
    B = loc[np.where(hst[loc] ^ False)]
    return hst, A, B